package com.lsq.mybatis;

import java.lang.reflect.*;
import java.sql.*;
import java.util.*;

/**
 * @author lsq
 * @description TODO
 * @date 2023/9/11
 */
public class MapperProxyFactory {

    private static Map<Class, TypeHandler> typeHandlerMap = new HashMap<>();//赋值类型

    static {

        typeHandlerMap.put(String.class, new  StringTypeHandler());
        typeHandlerMap.put(Integer.class, new IntegerTypeHandler());

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public static <T> T getMapper(Class<T> mapper){
        Object proxyInstance = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{mapper}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //解析sql-》执行sql-》结果处理

                //1创建数据库链接
                Connection connection = DriverManager.getConnection("jdbc:mysql://", "root", "123456");

                Select select = method.getAnnotation(Select.class);
                String sql = select.value(); //select * from user where name = #{name}
                //参数名字匹配问好
                Map<String, Object> paramValue = new HashMap<>();
                Parameter[] parameters = method.getParameters();
                for (int i = 0; i < parameters.length; i++) {
                    Parameter parameter = parameters[i];
                    String value = parameter.getAnnotation(Param.class).value();
                    paramValue.put(parameter.getName(), args[i]);
                    paramValue.put(value, args[i]);
                }
                //解析sqlselect * from user where name = #{name} --》 select * from user where name = ?，生成映射map调用typeHandlerMap判断类型赋值

                //2构造preparestatement
                PreparedStatement statement = connection.prepareStatement("select * from user where name = ?");
                statement.setString(1, "参数");
                //3执行preparestatement执行sql
                statement.execute();
                ResultSet resultSet = statement.getResultSet();


                //4封装结果
                Object result = null;

                List<Object> list = new ArrayList<>();
                //判断返回类型
                Class resultType = null;
                Type genericReturnType = method.getGenericReturnType();
                if (genericReturnType instanceof Class){
                    //不是泛型
                    resultType = (Class) genericReturnType;
                } else if ( genericReturnType instanceof ParameterizedType){
                    //是泛型
                    Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                    resultType = (Class) actualTypeArguments[0];
                }
                //获取查询字段
                ResultSetMetaData metaData = resultSet.getMetaData();
                List<String> list1 = new ArrayList<>();
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    list1.add(metaData.getCatalogName(i+1));
                }
                //获取set方法
                Map<String, Method> hashMap = new HashMap<>();
                for (Method declaredMethod : resultType.getDeclaredMethods()) {
                    if (declaredMethod.getName().endsWith("set")){
                        String substring = declaredMethod.getName().substring(3);
                        substring = substring.substring(0, 1).toLowerCase(Locale.ROOT) + substring.substring(1);
                        hashMap.put(substring, declaredMethod);
                    }
                }

                while (resultSet.next()){
                    Object instance = resultType.newInstance();
                    //遍历字段
                    for (int i = 0; i < list1.size(); i++) {
                        String column = list1.get(i);
                        Method set = hashMap.get(column);

                        Class clazz = set.getParameterTypes()[0];
                        TypeHandler typeHandler = typeHandlerMap.get(clazz);
                        set.invoke(instance, typeHandler.getResult(resultSet, column));
                    }
                    list.add(instance);
                }


                if (method.getReturnType().equals(List.class)){
                    result = list;
                }else {
                    result = list.get(0);
                }


                //5关闭
                connection.close();

                return result;
            }
        });

        return (T) proxyInstance;
    }
}
